package cn.fengLone.pay.util.unionPay;

import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
import java.util.TreeMap;
import java.util.Map.Entry;








import sun.util.logging.resources.logging;
import cn.fengLone.pay.entity.PayInfo;
import cn.fengLone.pay.entity.UnionPayBackInfo;
import cn.fengLone.pay.entity.UnionPayFullInfo;
import cn.fengLone.pay.util.SimpleUtil;
import cn.fengLone.pay.util.SpringUtil;
import cn.fengLone.pay.util.unionPay.sdk.AcpService;
import cn.fengLone.pay.util.unionPay.sdk.LogUtil;
import cn.fengLone.pay.util.unionPay.sdk.SDKConfig;
import cn.fengLone.pay.util.unionPay.sdk.SDKConstants;


/**
 * 
 * @description 银联支付工具类
 * 
 * @compny 深圳风轮科技有限公司
 * 
 * @author Guo PengFei
 * 
 * @date 2017-09-06
 * 
 * @version V1.0
 *
 */
public class UnionPayUtil {
	
	/**
	 * 银联PC网关/手机WEB支付接口
	 * @param unionPayFullInfo 银联网关支付配置信息
	 * @param payInfo  订单信息
	 * @return
	 * @throws Exception
	 */
	public static String B2CGateWayPay(UnionPayFullInfo unionPayFullInfo,  PayInfo payInfo) throws Exception{
		Map<String, String> requestData = new HashMap<String, String>();
		
		/***银联全渠道系统，产品参数，除了encoding自行选择外其他不需修改***/
		requestData.put("version", SimpleUtil.b2CGateWayMap.get("version"));   			  //版本号，全渠道默认值
		requestData.put("encoding", SimpleUtil.b2CGateWayMap.get("encoding")); 			  //字符集编码，可以使用UTF-8,GBK两种方式
		requestData.put("signMethod", "01");            			  //签名方法，只支持 01：RSA方式证书加密
		requestData.put("txnType", "01");               			  //交易类型 ，01：消费
		requestData.put("txnSubType", "01");            			  //交易子类型， 01：自助消费
		requestData.put("bizType", payInfo.getPayType());           			  //业务类型，B2C网关支付，手机wap支付
		requestData.put("channelType", payInfo.getChannelType());           			  //渠道类型，这个字段区分B2C网关支付和手机wap支付；07：PC,平板  08：手机
		
		/***商户接入参数***/
		requestData.put("merId", unionPayFullInfo.getMchID());    	          			  //商户号码，请改成自己申请的正式商户号或者open上注册得来的777测试商户号
		requestData.put("accessType", "0");             			  //接入类型，0：直连商户 
		requestData.put("orderId",payInfo.getTradeNum());             //商户订单号，8-40位数字字母，不能含“-”或“_”，可以自行定制规则		
		requestData.put("txnTime", SimpleUtil.getCurrentTime());        //订单发送时间，取系统时间，格式为YYYYMMDDhhmmss，必须取当前时间，否则会报txnTime无效
		requestData.put("currencyCode", "156");         			  //交易币种（境内商户一般是156 人民币）		
		requestData.put("txnAmt", payInfo.getTotal_fee());             			      //交易金额，单位分，不要带小数点
		//requestData.put("reqReserved", "透传字段");        		      //请求方保留域，如需使用请启用即可；透传字段（可以实现商户自定义参数的追踪）本交易的后台通知,对本交易的交易状态查询交易、对账文件中均会原样返回，商户可以按需上传，长度为1-1024个字节		
		
		//前台通知地址 （需设置为外网能访问 http https均可），支付成功后的页面 点击“返回商户”按钮的时候将异步通知报文post到该地址
		//如果想要实现过几秒中自动跳转回商户页面权限，需联系银联业务申请开通自动返回商户权限
		//异步通知参数详见open.unionpay.com帮助中心 下载  产品接口规范  网关支付产品接口规范 消费交易 商户通知
		requestData.put("frontUrl", SimpleUtil.b2CGateWayMap.get("synNotifyUrl"));
		
		//后台通知地址（需设置为【外网】能访问 http https均可），支付成功后银联会自动将异步通知报文post到商户上送的该地址，失败的交易银联不会发送后台通知
		//后台通知参数详见open.unionpay.com帮助中心 下载  产品接口规范  网关支付产品接口规范 消费交易 商户通知
		//注意:1.需设置为外网能访问，否则收不到通知    2.http https均可  3.收单后台通知后需要10秒内返回http200或302状态码 
		//    4.如果银联通知服务器发送通知后10秒内未收到返回状态码或者应答码非http200，那么银联会间隔一段时间再次发送。总共发送5次，每次的间隔时间为0,1,2,4分钟。
		//    5.后台通知地址如果上送了带有？的参数，例如：http://abc/web?a=b&c=d 在后台通知处理程序验证签名之前需要编写逻辑将这些字段去掉再验签，否则将会验签失败
		requestData.put("backUrl", SimpleUtil.b2CGateWayMap.get("asynNotifyUrl"));
		
		//////////////////////////////////////////////////
		//
		//       报文中特殊用法请查看 PCwap网关跳转支付特殊用法.txt
		//
		//////////////////////////////////////////////////
		
		/**请求参数设置完毕，以下对请求参数进行签名并生成html表单，将表单写入浏览器跳转打开银联页面**/
		Map<String, String> submitFromData = AcpService.sign(requestData,unionPayFullInfo.getCertPath(),unionPayFullInfo.getMchKey(),SimpleUtil.b2CGateWayMap.get("encoding"));  //报文中certId,signature的值是在signData方法中获取并自动赋值的，只要证书配置正确即可。
		
		String requestFrontUrl = SDKConfig.getConfig().getFrontRequestUrl();  //获取请求银联的前台地址：对应属性文件acp_sdk.properties文件中的acpsdk.frontTransUrl
		String html = AcpService.createAutoFormHtml(requestFrontUrl, submitFromData,SimpleUtil.b2CGateWayMap.get("encoding"));   //生成自动跳转的Html表单
		
		LogUtil.writeLog("打印请求HTML，此为请求报文，为联调排查问题的依据："+html);
		//将生成的html写到浏览器中完成自动跳转打开银联支付页面；这里调用signData之后，将html写到浏览器跳转到银联页面之前均不能对html中的表单项的名称和值进行修改，如果修改会导致验签不通过

		return html;
		
	}
	
	
	
	/**
	 * 银联支付撤销订单接口实现类，同步结果不是处理结果，需要异步返回结果或者主动查询业务处理状态
	 * @param unionPayFullInfo 银联网关支付配置信息
	 * @param unionPayBackInfo  撤销订单信息
	 * @param payType 支付方式
	 * @param channelType 渠道类别
	 * @return
	 * @throws Exception
	 */
	public static Map<String, String> B2CGateWayRevoke(UnionPayFullInfo unionPayFullInfo,UnionPayBackInfo unionPayBackInfo ,String payType,String channelType) throws Exception{

		Map<String, String> resultMap = new HashMap<String, String>();
		
		Map<String, String> data = new HashMap<String, String>();
		
		/***银联全渠道系统，产品参数，除了encoding自行选择外其他不需修改***/
		data.put("version", SimpleUtil.b2CGateWayMap.get("version"));   			  //版本号，全渠道默认值
		data.put("encoding", SimpleUtil.b2CGateWayMap.get("encoding")); 			  //字符集编码，可以使用UTF-8,GBK两种方式
		data.put("signMethod", "01");                     //签名方法 目前只支持01-RSA方式证书加密
		data.put("txnType", "31");                        //交易类型 31-消费撤销
		data.put("txnSubType", "00");                     //交易子类型  默认00
		data.put("bizType", payType);                    
		data.put("channelType", channelType);                    //渠道类型，07-PC，08-手机
		
		/***商户接入参数***/
		data.put("merId", unionPayFullInfo.getMchID());             //商户号码，请改成自己申请的商户号或者open上注册得来的777商户号测试
		data.put("accessType", "0");                      //接入类型，商户接入固定填0，不需修改	
		data.put("orderId", unionPayBackInfo.getTradeNum());       //商户订单号，8-40位数字字母，不能含“-”或“_”，可以自行定制规则，重新产生，不同于原消费		
		data.put("txnTime", SimpleUtil.getCurrentTime(unionPayBackInfo.getCreateTime()));   //订单发送时间，格式为YYYYMMDDhhmmss，必须取当前时间，否则会报txnTime无效
		data.put("txnAmt", unionPayBackInfo.getTotal_fee());                       //【撤销金额】，消费撤销时必须和原消费金额相同	
		data.put("currencyCode", "156");                  //交易币种(境内商户一般是156 人民币)
		//data.put("reqReserved", "透传信息");                 //请求方保留域，，如需使用请启用即可；透传字段（可以实现商户自定义参数的追踪）本交易的后台通知,对本交易的交易状态查询交易、对账文件中均会原样返回，商户可以按需上传，长度为1-1024个字节		
		data.put("backUrl", SimpleUtil.b2CGateWayMap.get("asynNotifyUrl"));            //后台通知地址，后台通知参数详见open.unionpay.com帮助中心 下载  产品接口规范  网关支付产品接口规范 消费撤销交易 商户通知,其他说明同消费交易的商户通知
		
		
		/***要调通交易以下字段必须修改***/
		data.put("origQryId", unionPayBackInfo.getBackQueryId());   			  //【原始交易流水号】，原消费交易返回的的queryId，可以从消费交易后台通知接口中或者交易状态查询接口中获取
		
		/**请求参数设置完毕，以下对请求参数进行签名并发送http post请求，接收同步应答报文**/
//		Map<String, String> reqData  = AcpService.sign(data,SimpleUtil.b2CGateWayMap.get("encoding"));//报文中certId,signature的值是在signData方法中获取并自动赋值的，只要证书配置正确即可。
		Map<String, String> reqData  = AcpService.sign(data,unionPayFullInfo.getCertPath(),unionPayFullInfo.getMchKey(),SimpleUtil.b2CGateWayMap.get("encoding"));//报文中certId,signature的值是在signData方法中获取并自动赋值的，只要证书配置正确即可。
		
		
		
		String reqUrl = SDKConfig.getConfig().getBackRequestUrl();//交易请求url从配置文件读取对应属性文件acp_sdk.properties中的 acpsdk.backTransUrl
		
		//此处需要注意，验签时的certId（相当于密钥）为从银联数据中获取，监控是否为正确的certId
		Map<String,String> rspData = AcpService.post(reqData,reqUrl,SimpleUtil.b2CGateWayMap.get("encoding"));//发送请求报文并接受同步应答（默认连接超时时间30秒，读取返回结果超时时间30秒）;这里调用signData之后，调用submitUrl之前不能对submitFromData中的键值对做任何修改，如果修改会导致验签不通过

		/**对应答码的处理，请根据您的业务逻辑来编写程序,以下应答码处理逻辑仅供参考------------->**/
		
		
		String reqMessage = genHtmlResult(reqData);
		String rspMessage = genHtmlResult(rspData);
		LogUtil.writeMessage("---------------撤销订单时的发送的报文为:-------------------");
		LogUtil.writeMessage(reqMessage);
		LogUtil.writeMessage("---------------撤销订单时接收到的报文为:-------------------");
		LogUtil.writeMessage(rspMessage);
		
		//应答码规范参考open.unionpay.com帮助中心 下载  产品接口规范  《平台接入接口规范-第5部分-附录》
		if(!rspData.isEmpty()){
			if(AcpService.validate(rspData, SimpleUtil.b2CGateWayMap.get("encoding"))){
				LogUtil.writeLog("验证签名成功");
				String respCode = rspData.get("respCode");
				if("00".equals(respCode)){
					//交易已受理(不代表交易已成功），等待接收后台通知确定交易成功，也可以主动发起 查询交易确定交易状态。
					//TODO
					System.out.println("撤单交易(tradeNum=\""+unionPayBackInfo.getTradeNum()+"\";out_radeNum=\""+unionPayBackInfo.getMertradeNum()+"\")已经受理------ respCode = 00");
					resultMap.put("return_code", "1");
					resultMap.put("return_msg", "撤单交易(tradeNum=\""+unionPayBackInfo.getTradeNum()+"\";out_radeNum=\""+unionPayBackInfo.getMertradeNum()+"\")已经受理------ respCode = "+respCode+"，稍后将会更新订单状态.");
				}else if("03".equals(respCode) ||
						 "04".equals(respCode) ||
						 "05".equals(respCode)){
					//后续需发起交易状态查询交易确定交易状态。
					//TODO
					System.out.println("撤单交易(tradeNum=\""+unionPayBackInfo.getTradeNum()+"\";out_radeNum=\""+unionPayBackInfo.getMertradeNum()+"\")已经受理------ respCode = "+respCode+",但是需要后续主动查询该订单状态!");
					resultMap.put("return_code", "1");
					resultMap.put("return_msg", "撤单交易(tradeNum=\""+unionPayBackInfo.getTradeNum()+"\";out_radeNum=\""+unionPayBackInfo.getMertradeNum()+"\")已经受理------ respCode = "+respCode+",但是需要后续主动查询该订单状态!");
				
				}else{
					//其他应答码为失败请排查原因
					//TODO
					resultMap.put("return_code", "0");
					resultMap.put("return_msg", "撤单交易(tradeNum=\""+unionPayBackInfo.getTradeNum()+"\";out_radeNum=\""+unionPayBackInfo.getMertradeNum()+"\")处理发生错误------ respCode = "+respCode);
				}
			}else{
				LogUtil.writeErrorLog(SpringUtil.getI18nMsg("decode_val_error"));
				//TODO 检查验证签名失败的原因
				resultMap.put("return_code", "0");
				resultMap.put("return_msg", SpringUtil.getI18nMsg("decode_val_error"));
			}
			return resultMap;
		}else{
			//未返回正确的http状态
			LogUtil.writeErrorLog(SpringUtil.getI18nMsg("unionPay_revoke_error"));
			resultMap.put("return_code", "0");
			resultMap.put("return_msg", SpringUtil.getI18nMsg("unionPay_revoke_error"));
			return resultMap;
		}
	
	}
	
	
	
	
	/**
	 * 组装请求，返回报文字符串用于显示
	 * 
	 * @param data
	 * @return
	 */
	private static String genHtmlResult(Map<String, String> data) {

		TreeMap<String, String> tree = new TreeMap<String, String>();
		Iterator<Entry<String, String>> it = data.entrySet().iterator();
		while (it.hasNext()) {
			Entry<String, String> en = it.next();
			tree.put(en.getKey(), en.getValue());
		}
		it = tree.entrySet().iterator();
		StringBuffer sf = new StringBuffer();
		while (it.hasNext()) {
			Entry<String, String> en = it.next();
			String key = en.getKey();
			String value = en.getValue();
			if ("respCode".equals(key)) {
				sf.append("<b>" + key + SDKConstants.EQUAL + value
						+ "</br></b>");
			} else
				sf.append(key + SDKConstants.EQUAL + value + "</br>");
		}
		return sf.toString();
	}



	/**
	 * 查询订单 状态
	 * @param unionPayFullInfo  银联支付配置
	 * @param payInfo  订单
	 * @return
	 */
	public static Map<String, String> queryOrder(
			UnionPayFullInfo unionPayFullInfo, PayInfo payInfo) {
		
		Map<String, String> resultMap = new HashMap<String, String>();
		
		Map<String, String> data = new HashMap<String, String>();

		/*** 银联全渠道系统，产品参数，除了encoding自行选择外其他不需修改 ***/

		// 版本号

		data.put("version", SimpleUtil.b2CGateWayMap.get("version"));   

		// 字符集编码 可以使用UTF-8,GBK两种方式

		data.put("encoding", SimpleUtil.b2CGateWayMap.get("encoding"));

		data.put("signMethod", "01");                          //签名方法 目前只支持01-RSA方式证书加密
		data.put("txnType", "00");                             //交易类型 00-默认
		data.put("txnSubType", "00");                          //交易子类型  默认00
		data.put("bizType", payInfo.getPayType());                         //业务类型 B2C网关支付，手机wap支付
		

		/*** 商户接入参数 ***/

		// 商户号码，请改成自己申请的商户号或者open上注册得来的777商户号测试

		data.put("merId", unionPayFullInfo.getMchID());

		// 接入类型，商户接入固定填0，不需修改

		data.put("accessType", "0");

		/*** 要调通交易以下字段必须修改 ***/

		// ****商户订单号，每次发交易测试需修改为被查询的交易的订单号

		data.put("orderId", payInfo.getTradeNum());

		// ****订单发送时间，每次发交易测试需修改为被查询的交易的订单发送时间

		data.put("txnTime", SimpleUtil.getCurrentTime(payInfo.getCreateTime()));

		/** 请求参数设置完毕，以下对请求参数进行签名并发送http post请求，接收同步应答报文-------------> **/

		// 报文中certId,signature的值是在signData方法中获取并自动赋值的，只要证书配置正确即可。

		
		/**请求参数设置完毕，以下对请求参数进行签名并生成html表单，将表单写入浏览器跳转打开银联页面**/
		Map<String, String> reqData = AcpService.sign(data,unionPayFullInfo.getCertPath(),unionPayFullInfo.getMchKey(),SimpleUtil.b2CGateWayMap.get("encoding"));  //报文中certId,signature的值是在signData方法中获取并自动赋值的，只要证书配置正确即可。
		
		
		// 交易请求url从配置文件读取对应属性文件acp_sdk.properties中的 acpsdk.singleQueryUrl

		String url = SDKConfig.getConfig().getSingleQueryUrl();

		// 发送请求报文并接受同步应答（默认连接超时时间30秒，读取返回结果超时时间30秒）;这里调用signData之后，

		// 调用submitUrl之前不能对submitFromData中的键值对做任何修改，如果修改会导致验签不通过

		Map<String, String> rspData = AcpService.post(reqData, url,
				SimpleUtil.b2CGateWayMap.get("encoding"));

		// 应答码规范参考open.unionpay.com帮助中心 下载 产品接口规范 《平台接入接口规范-第5部分-附录》

		if (!rspData.isEmpty()) {

			if (AcpService.validate(rspData, SimpleUtil.b2CGateWayMap.get("encoding"))) {
				LogUtil.writeLog("验证签名成功");
				if("00".equals(rspData.get("respCode"))){//如果查询交易成功
					//处理被查询交易的应答码逻辑
					String origRespCode = rspData.get("origRespCode");
					if("00".equals(origRespCode)){
						//交易成功，更新商户订单状态
						resultMap.put("recode_code", "SUCCESS");
						resultMap.putAll(rspData);
					}else if("03".equals(origRespCode) ||
							 "04".equals(origRespCode) ||
							 "05".equals(origRespCode)){
						//需再次发起交易状态查询交易 
						//TODO
//						resultMap.putAll(rspData);
						resultMap.put("recode_code", "FAIL");
						resultMap.put("recode_msg", SpringUtil.getI18nMsg("order_result_no"));
					}else{
						//其他应答码为失败请排查原因
						//TODO
						resultMap.put("recode_code", "FAIL");
						resultMap.put("recode_msg", SpringUtil.getI18nMsg("uniPay_order_error"));
					
					}
				}else{//查询交易本身失败，或者未查到原交易，检查查询交易报文要素
					resultMap.put("recode_code", "FAIL");
					resultMap.put("recode_msg", SpringUtil.getI18nMsg("system_error"));
				}
			} else {

				LogUtil.writeErrorLog("验证签名失败");

				// TODO 检查验证签名失败的原因
				resultMap.put("recode_code", "FAIL");
				resultMap.put("recode_msg", SpringUtil.getI18nMsg("decode_val_error"));
			
			}

		} else {

			// 未返回正确的http状态
			resultMap.put("recode_code", "FAIL");
			resultMap.put("recode_msg", SpringUtil.getI18nMsg("unionPay_revoke_error"));
			LogUtil.writeErrorLog("未获取到返回报文或返回http状态码非200");
		}
		
		return resultMap;
	}



	/**
	 * B2C退货
	 * @param payInfo  订单
	 * @param unionPayFullInfo  银联支付配置
	 * @return
	 */
	public static Map<String, String> B2CGateWayBackTrans(PayInfo payInfo,
			UnionPayFullInfo unionPayFullInfo) {
		Map<String, String> resultMap = new HashMap<String, String>();
		Map<String, String> data = new HashMap<String, String>();
		/*** 银联全渠道系统，产品参数，除了encoding自行选择外其他不需修改 ***/
		// 版本号
		data.put("version", SimpleUtil.b2CGateWayMap.get("version"));
		// 字符集编码 可以使用UTF-8,GBK两种方式
		data.put("encoding", SimpleUtil.b2CGateWayMap.get("encoding"));
		// 签名方法
		data.put("signMethod", "01");
		// 交易类型 04-退货
		data.put("txnType", "04");
		// 交易子类型 默认00
		data.put("txnSubType", "00");
		// 业务类型
		data.put("bizType", payInfo.getPayType());
		// 渠道类型，07-PC，08-手机
		data.put("channelType", payInfo.getChannelType());
		/*** 商户接入参数 ***/
		// 商户号码，请改成自己申请的商户号或者open上注册得来的777商户号测试
		data.put("merId", unionPayFullInfo.getMchID());
		// 接入类型，商户接入固定填0，不需修改
		data.put("accessType", "0");
		// 商户订单号，8-40位数字字母，不能含“-”或“_”，可以自行定制规则，重新产生，不同于原消费
		data.put("orderId", payInfo.getTradeNum()+"TH"); //退货时的订单号不保存，且订单号后加TH（退货）
		// 订单发送时间，格式为YYYYMMDDhhmmss，必须取当前时间，否则会报txnTime无效
		data.put("txnTime", SimpleUtil.getCurrentTime());
		// 交易币种（境内商户一般是156 人民币）
		data.put("currencyCode", "156");
		// ****退货金额，单位分，不要带小数点。退货金额小于等于原消费金额，当小于的时候可以多次退货至退货累计金额等于原消费金额
		data.put("txnAmt", payInfo.getTotal_fee());
		// 后台通知地址，后台通知参数详见open.unionpay.com帮助中心 下载 产品接口规范 网关支付产品接口规范 退货交易
		// 商户通知,其他说明同消费交易的后台通知
		data.put("backUrl", SimpleUtil.b2CGateWayMap.get("asynNotifyUrl"));
		/*** 要调通交易以下字段必须修改 ***/
		// ****原消费交易返回的的queryId，可以从消费交易后台通知接口中或者交易状态查询接口中获取
		data.put("origQryId", payInfo.getQueryId());
		/** 请求参数设置完毕，以下对请求参数进行签名并发送http post请求，接收同步应答报文-------------> **/
		// 报文中certId,signature的值是在signData方法中获取并自动赋值的，只要证书配置正确即可。
		Map<String, String> reqData  = AcpService.sign(data,unionPayFullInfo.getCertPath(),unionPayFullInfo.getMchKey(),SimpleUtil.b2CGateWayMap.get("encoding"));//报文中certId,signature的值是在signData方法中获取并自动赋值的，只要证书配置正确即可。
		// 交易请求url从配置文件读取对应属性文件acp_sdk.properties中的 acpsdk.backTransUrl
		String url = SDKConfig.getConfig().getBackRequestUrl();
		// 这里调用signData之后，调用submitUrl之前不能对submitFromData中的键值对做任何修改，如果修改会导致验签不通过
		Map<String, String> rspData = AcpService.post(reqData, url,
				SimpleUtil.b2CGateWayMap.get("encoding"));
		// 应答码规范参考open.unionpay.com帮助中心 下载 产品接口规范 《平台接入接口规范-第5部分-附录》
		if (!rspData.isEmpty()) {
			if (AcpService.validate(rspData, SimpleUtil.b2CGateWayMap.get("encoding"))) {
				LogUtil.writeLog("验证签名成功");
				String respCode = rspData.get("respCode");
				if (("00").equals(respCode)) {
					String queryId = rspData.get("queryId"); //退货是的交易流水号
					
					// 交易已受理(不代表交易已成功），等待接收后台通知更新订单状态,也可以主动发起 查询交易确定交易状态。
					resultMap.put("return_code", "1");
					resultMap.put("queryId", queryId);
					
				} else if (("03").equals(respCode) || ("04").equals(respCode) || ("05").equals(respCode)) {
					String queryId = rspData.get("queryId"); //退货是的交易流水号
					
					// 后续需发起交易状态查询交易确定交易状态
					resultMap.put("return_code", "1");
					resultMap.put("queryId", queryId);
				} else {
					// 其他应答码为失败请排查原因
					resultMap.put("return_code", "0");
					resultMap.put("return_msg", SpringUtil.getI18nMsg("pay_resp_code_error")+"----"+respCode);
				}
			} else {
				LogUtil.writeErrorLog("验证签名失败");
				// TODO 检查验证签名失败的原因
				resultMap.put("return_code", "0");
				resultMap.put("return_msg", SpringUtil.getI18nMsg("decode_val_error"));
			}
		} else {
			// 未返回正确的http状态
			LogUtil.writeErrorLog("未获取到返回报文或返回http状态码非200");
			resultMap.put("return_code", "0");
			resultMap.put("return_msg", SpringUtil.getI18nMsg("unionPay_revoke_error"));
		}
		return resultMap;
	}

	
	public static Map<String, String> downloadBillFile(
			UnionPayFullInfo unionPayFullInfo,String queryDate) {
		Map<String, String> resultMap = new HashMap<String, String>();

		Map<String, String> data = new HashMap<String, String>();

		/*** 银联全渠道系统，产品参数，除了encoding自行选择外其他不需修改 ***/

		// 版本号 全渠道默认值

		data.put("version", SimpleUtil.b2CGateWayMap.get("version"));
		
		// 字符集编码 可以使用UTF-8,GBK两种方式

		data.put("encoding", SimpleUtil.b2CGateWayMap.get("encoding"));

		// 签名方法

		data.put("signMethod", "01");

		// 交易类型 76-对账文件下载

		data.put("txnType", "76");

		// 交易子类型 01-对账文件下载

		data.put("txnSubType", "01");

		// 业务类型，固定

		data.put("bizType", "000000");

		/*** 商户接入参数 ***/

		// 接入类型，商户接入填0，不需修改

		data.put("accessType", "0");

		// 商户代码，请替换正式商户号测试，如使用的是自助化平台注册的777开头的商户号，该商户号没有权限测文件下载接口的，

		// 请使用测试参数里写的文件下载的商户号和日期测。如需777商户号的真实交易的对账文件，请使用自助化平台下载文件。

		data.put("merId", unionPayFullInfo.getMchID());
		//订单发送时间，取系统时间，格式为YYYYMMDDhhmmss，必须取当前时间，否则会报txnTime无效 

		data.put("txnTime",SimpleUtil.getCurrentTime()); 

		// 清算日期，如果使用正式商户号测试则要修改成自己想要获取对账文件的日期，
		// 测试环境如果使用700000000000001商户号则固定填写0119

		data.put("settleDate", queryDate);


		// 文件类型，一般商户填写00即可

		data.put("fileType", "00");

		/** 请求参数设置完毕，以下对请求参数进行签名并发送http post请求，接收同步应答报文-------------> **/

//		Map<String, String> reqData = AcpService.sign(data,
//				SimpleUtil.b2CGateWayMap.get("encoding"));
		Map<String, String> reqData = AcpService.sign(data,unionPayFullInfo.getCertPath(),unionPayFullInfo.getMchKey(),
				SimpleUtil.b2CGateWayMap.get("encoding"));
		
		// 报文中certId,signature的值是在signData方法中获取并自动赋值的，只要证书配置正确即可。

//		String url = SDKConfig.getConfig().getFileTransUrl();
		String url = "https://101.231.204.80:9080/";
		// 获取请求银联的前台地址：对应属性文件acp_sdk.properties文件中的acpsdk.fileTransUrl

		Map<String, String> rspData = AcpService.post(reqData, url,
				SimpleUtil.b2CGateWayMap.get("encoding"));

		if (!rspData.isEmpty()) {

			if (AcpService.validate(rspData, SimpleUtil.b2CGateWayMap.get("encoding"))) {

				LogUtil.writeLog("验证签名成功");

				String respCode = rspData.get("respCode");

				if ("00".equals(respCode)) {

					// 交易成功，解析返回报文中的fileContent并落地

					AcpService.deCodeFileContent(rspData,"D:\\aaaa\\",SimpleUtil.b2CGateWayMap.get("encoding"));
					System.out.println("对账文件落地成功");
					resultMap.put("return_code", "1");
				} else {
					System.out.println("对账文件落地失败....");
					System.out.println(rspData);
					// 其他应答码为失败请排查原因
					// 未返回正确的http状态
					LogUtil.writeErrorLog("未获取到返回报文或返回http状态码非200");
					resultMap.put("return_code", "0");
					resultMap.put("return_msg", SpringUtil.getI18nMsg("unionPay_revoke_error"));
				}
			} else {
				LogUtil.writeErrorLog("验证签名失败");
				resultMap.put("return_code", "0");
				resultMap.put("return_msg", "验证签名失败");
			}
		} else {
			// 未返回正确的http状态
			LogUtil.writeErrorLog("未获取到返回报文或返回http状态码非200");
			resultMap.put("return_code", "0");
			resultMap.put("return_msg", "未获取到返回报文或返回http状态码非200");
		}
		return resultMap;
	}
	
}
